//---------------------------
// Includes
//---------------------------
#include "StdAfx.h"
#include "SkyBox.h"
#include "Level.h"
#include "GraphCamera.h"

//---------------------------
// Constructor & Destructor
//---------------------------
SkyBox::SkyBox(Level* level, const tstring& fileName)
	:LevelElement()
	,m_pVertexLayout(0)
	,m_pVertexBuffer(0)
	,m_pIndexBuffer(0)
	,m_pDefaultEffect(0)	
	,m_pDefaultTechnique(0)
	,m_pCubeMap(0)
	,m_pCubeMapVariable(0)
	,m_pWorldViewProjectionVariable(NULL)
	,m_TexFileName(fileName)
{
	// nothing to create
	m_pLevel = level;
}

SkyBox::~SkyBox()
{
	SafeRelease(m_pVertexBuffer );
	SafeRelease(m_pVertexLayout);
}

void SkyBox::Initialize(ContentManager *pContentManager)
{
	CreateEffect(pContentManager);
	DefineInputlayout();
	BuildShape();
	BuildVertexBuffer();
	BuildIndexBuffer();

	m_pCubeMap = pContentManager->GetCubeMap(m_pLevel->GetDevice(),m_TexFileName);
}
void SkyBox::Draw(const RenderContext* pRenderContext, ID3D10ShaderResourceView* shadowdepthmap)
{
	if(!m_pDefaultTechnique )
	{
		MessageBox(0,_T("No Technique"),_T("ERROR"),0);
		return;
	}
	if(!m_pVertexBuffer)
	{
		MessageBox(0,_T("No Vertices"),_T("ERROR"),0);
		return;
	}	
	// Update Shader matrix variables
	D3DXMATRIX matView = pRenderContext->GetCamera()->GetView();
	D3DXMATRIX matProj = pRenderContext->GetCamera()->GetProj();

	m_pWorldViewProjectionVariable->SetMatrix((float*)&(m_World*matView*matProj));
	//m_pWorldVariable->SetMatrix((float*)&(m_World));

	//D3DXVECTOR3 lightDir = pRenderContext->GetLight().DirW;
	//m_pLightDirVariabele->SetFloatVectorArray(&lightDir.x,0,sizeof(D3DXVECTOR3)/sizeof(float));

	m_pCubeMapVariable->SetResource(m_pCubeMap);
	// Set the input layout
    m_pLevel->GetDevice()->IASetInputLayout( m_pVertexLayout );

    // Set vertex buffer(s)
    UINT offset = 0;
	UINT vertexBufferStride = sizeof(VertexPos);
    m_pLevel->GetDevice()->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &vertexBufferStride, &offset );
   	
	// Set index buffer
	m_pLevel->GetDevice()->IASetIndexBuffer(m_pIndexBuffer,DXGI_FORMAT_R32_UINT,0);

    // Set primitive topology
    m_pLevel->GetDevice()->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

    D3D10_TECHNIQUE_DESC techDesc;
    m_pDefaultTechnique->GetDesc( &techDesc );
    for( UINT p = 0; p < techDesc.Passes; ++p )
    {
        m_pDefaultTechnique->GetPassByIndex(p)->Apply(0);
		m_pLevel->GetDevice()->DrawIndexed( m_VecIndices.size(), 0, 0 ); 
    }
}
void SkyBox::CreateEffect(ContentManager *pContentManager)
{
	m_pDefaultEffect = pContentManager->GetEffect(m_pLevel->GetDevice(),  _T("./Effect/SkyBox.fx"));
	
	//get first technique found
	m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByIndex(0);
	if(!m_pDefaultTechnique->IsValid())MessageBox(0,_T("Technique not valid"),_T("ERROR"),0);

	GetEffectVariables(m_pDefaultEffect);
}
void SkyBox::GetEffectVariables(ID3D10Effect* pEffect)
{
	m_pWorldViewProjectionVariable = pEffect->GetVariableBySemantic("WorldViewProj")->AsMatrix();
	if(!m_pWorldViewProjectionVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic WorldViewProjection Failed"),_T("ERROR"),0);

	m_pCubeMapVariable = pEffect->GetVariableBySemantic("CubeMap")->AsShaderResource();
	if(!m_pCubeMapVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic World Failed"),_T("ERROR"),0);
}
void SkyBox::DefineInputlayout()
{
	 D3D10_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }
    };
    UINT numElements = sizeof(layout)/sizeof(layout[0]);

    // Create the input layout
    D3D10_PASS_DESC PassDesc;
	// Get the pass decriptor from the effect technique
    m_pDefaultTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    HR(m_pLevel->GetDevice()->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &m_pVertexLayout ));
}
void SkyBox::BuildShape()
{
	//top front left0
	VertexPos v(-1, 1, 1);
	m_VecVertices.push_back(v);
	//top front right1
	v=VertexPos(1, 1, 1);
	m_VecVertices.push_back(v);
	//top back left2
	v=VertexPos(-1, 1, -1);
	m_VecVertices.push_back(v);
	//top back right3
	v=VertexPos(1, 1, -1);
	m_VecVertices.push_back(v);
	//bottom back left4
	v=VertexPos(-1, -1, -1);
	m_VecVertices.push_back(v);
	//bottom back right5
	v=VertexPos(1, -1, -1);
	m_VecVertices.push_back(v);
	//bottom front left6
	v=VertexPos(-1, -1, 1);
	m_VecVertices.push_back(v);
	//bottom front right7
	v=VertexPos(1, -1, 1);
	m_VecVertices.push_back(v);

	AddTriangle(0,1,2);//top
	AddTriangle(2,1,3);

	AddTriangle(2,3,4);//back
	AddTriangle(4,5,3);

	AddTriangle(4,5,6);//bottom
	AddTriangle(6,7,5);

	AddTriangle(0,1,6);//front
	AddTriangle(6,7,1);

	AddTriangle(0,2,4);//left
	AddTriangle(4,6,0);

	AddTriangle(1,3,5);//right
	AddTriangle(5,7,1);
}
void SkyBox::AddTriangle (unsigned int a, unsigned int b, unsigned c)
{
	m_VecIndices.push_back(a);
	m_VecIndices.push_back(b);
	m_VecIndices.push_back(c);
}
void SkyBox::BuildVertexBuffer()
{
	//fill a buffer description to copy the vertexdata into graphics memory
	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( VertexPos ) * m_VecVertices.size();
	bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;

	D3D10_SUBRESOURCE_DATA initData;
	initData.pSysMem = m_VecVertices.data();
	//create a ID3D10Buffer in graphics memory containing the vertex info
	HR(m_pLevel->GetDevice()->CreateBuffer( &bd, &initData, &m_pVertexBuffer ));
}
void SkyBox::BuildIndexBuffer()
{
	D3D10_BUFFER_DESC ibd;
    ibd.Usage = D3D10_USAGE_IMMUTABLE;
    ibd.ByteWidth = sizeof(DWORD) * m_VecIndices.size();
    ibd.BindFlags = D3D10_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
    ibd.MiscFlags = 0;
    D3D10_SUBRESOURCE_DATA initData;
    initData.pSysMem = m_VecIndices.data();
    HR(m_pLevel->GetDevice()->CreateBuffer(&ibd, &initData, &m_pIndexBuffer));
}
//---------------------------
// Eigen methoden
//---------------------------

// vul aan met je eigen methoden.


